package com.zkthink.ceres.tenant.service.impl;

import com.alibaba.fastjson.JSONObject;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.zkthink.base.R;
import com.zkthink.base.request.PageParams;
import com.zkthink.base.service.SuperServiceImpl;
import com.zkthink.cache.repository.CacheRepository;
import com.zkthink.ceres.common.constant.BizConstant;
import com.zkthink.ceres.common.constant.CacheKey;
import com.zkthink.ceres.sms.entity.SmsTask;
import com.zkthink.ceres.sms.enumeration.SourceType;
import com.zkthink.ceres.sms.enumeration.TemplateCodeType;
import com.zkthink.ceres.sms.enumeration.VerificationCodeType;
import com.zkthink.ceres.sms.service.SmsTaskService;
import com.zkthink.ceres.tenant.config.SiteUrlConfiguration;
import com.zkthink.ceres.tenant.dao.TenantApplyMapper;
import com.zkthink.ceres.tenant.dto.*;
import com.zkthink.ceres.tenant.entity.Tenant;
import com.zkthink.ceres.tenant.entity.TenantApply;
import com.zkthink.ceres.tenant.enumeration.TenantStatusEnum;
import com.zkthink.ceres.tenant.enums.OrganizationCodeEnum;
import com.zkthink.ceres.tenant.enums.TenantAuditStateEnum;
import com.zkthink.ceres.tenant.service.TenantApplyService;
import com.zkthink.ceres.tenant.service.TenantService;
import com.zkthink.exception.BizException;
import lombok.AllArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;
import java.util.List;
import java.util.Objects;
import java.util.Optional;

/**
 * <p>
 * 业务实现类
 * 商家入驻
 * </p>
 *
 * @author vivi.huang
 * @date 2020-06-28
 */
@Slf4j
@Service
@AllArgsConstructor
public class TenantApplyServiceImpl extends SuperServiceImpl<TenantApplyMapper, TenantApply> implements TenantApplyService {

    private static Integer REMOTE_EXPIRE_LIMIT_YEAR = 3;

    private TenantApplyMapper tenantApplyMapper;
    private TenantService tenantService;
    private CacheRepository cacheRepository;
    private SmsTaskService smsTaskService;

    private SiteUrlConfiguration siteUrlConfiguration;

    @Override
    public R<IPage<TenantApply>> findTenantApplyPage(PageParams<TenantApplyPageDTO> params) {
        IPage<TenantApply> page = params.getPage();
        queryTenantApply(params, page);
        return R.success(page);
    }

    @Override
    public R<TenantApply> getTenantApply(Long id) {
        return R.success(this.tenantApplyMapper.getTenantApply(id));
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public R<Boolean> audit(TenantApplyAuditDTO tenantApplyAuditDTO) {

        tenantApplyAuditDTO.setAuditTime(LocalDateTime.now());

        if (isAuditSuccess(tenantApplyAuditDTO)) {
            //增加商家
            Tenant tenant = saveTenant(tenantApplyAuditDTO);
            //更新入驻详情
            updateTenantApplyData(Optional.ofNullable(tenant), tenantApplyAuditDTO);
            //发送短信通知
            sendMessageOfTenantApply(tenantApplyAuditDTO, true);
        } else {
            //更新入驻详情
            updateTenantApplyData(Optional.empty(), tenantApplyAuditDTO);
            sendMessageOfTenantApply(tenantApplyAuditDTO, false);
        }

        return R.success();
    }

    private void updateTenantApplyData(Optional<Tenant> tenantOptional, TenantApplyAuditDTO tenantApplyAuditDTO) {
        this.tenantApplyMapper.auditTenantApply(tenantApplyAuditDTO.getId(),
                DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss").format(tenantApplyAuditDTO.getAuditTime()),
                tenantApplyAuditDTO.getAuditState(), tenantApplyAuditDTO.getRejectReason(),
                tenantApplyAuditDTO.getEffectDateType(), tenantApplyAuditDTO.getEffectTime(),
                tenantApplyAuditDTO.getEffectTimeLimit(), tenantOptional.map(t -> t.getCode()).orElse(""));
    }

    private void sendMessageOfTenantApply(TenantApplyAuditDTO tenantApplyAuditDTO, boolean isSuccess) {
        SmsTask smsTask = SmsTask.builder().build();
        smsTask.setSourceType(SourceType.SERVICE);

        if (isSuccess) {
            smsTask.setTemplateParams(getSuccessTemplateParams(tenantApplyAuditDTO));
        } else {
            smsTask.setTemplateParams(getFailTemplateParams(tenantApplyAuditDTO));
        }

        TenantApply tenantApply = this.getTenantApply(tenantApplyAuditDTO.getId()).getData();
        smsTask.setReceiver(tenantApply.getHeadMobile());
        smsTask.setDraft(false);

        smsTaskService.saveTask(smsTask, isSuccess ? TemplateCodeType.CODE_TENANT_APPLY_SUCCESS : TemplateCodeType.CODE_TENANT_APPLY_FAIL);

    }

    private String getSuccessTemplateParams(TenantApplyAuditDTO tenantApplyAuditDTO) {
        JSONObject param = new JSONObject();
        //默认密码
        param.put("1", BizConstant.DEF_PASSWORD);
        //商家端登录链接
        param.put("2", siteUrlConfiguration.getTenantLoginPage());
        return param.toString();
    }

    private String getFailTemplateParams(TenantApplyAuditDTO tenantApplyAuditDTO) {
        JSONObject param = new JSONObject();
        //失败原因
        param.put("1", tenantApplyAuditDTO.getRejectReason());
        //商家入驻申请链接
        param.put("2", siteUrlConfiguration.getTenantApplyPage());
        return param.toString();
    }

    private boolean isAuditSuccess(TenantApplyAuditDTO tenantApplyAuditDTO) {
        return  TenantAuditStateEnum.PASSED.getCode() == tenantApplyAuditDTO.getAuditState().intValue();
    }

    private Tenant saveTenant(TenantApplyAuditDTO tenantApplyAuditDTO) {

        //查询商户申请信息
        R<TenantApply> result = this.getTenantApply(tenantApplyAuditDTO.getId());
        TenantApply tenantApply = result.getData();

        if (Objects.nonNull(tenantApply)) {
            TenantSaveDTO tenantSaveDTO = new TenantSaveDTO();
            tenantSaveDTO.setStatus(TenantStatusEnum.NORMAL);
            tenantSaveDTO.setName(getTenantName(tenantApply));
            tenantSaveDTO.setDuty(tenantApply.getStoreHead());
            tenantSaveDTO.setContactTel(tenantApply.getHeadMobile());
            tenantSaveDTO.setAddress(createTenantAddress(tenantApply));
            tenantSaveDTO.setStartTime(LocalDateTime.now());
            tenantSaveDTO.setExpireLimitYear(REMOTE_EXPIRE_LIMIT_YEAR);
            tenantSaveDTO.setMobile(tenantApply.getHeadMobile());
            Tenant tenant = tenantService.save(tenantSaveDTO);
            log.info("调研添加商家接口成功");
            return tenant;
        } else {
            throw new BizException("商家入驻信息为空，审核失败");
        }

    }

    private String getTenantName(TenantApply tenantApply) {
        if (StringUtils.isNotBlank(tenantApply.getStoreName())) {
            return tenantApply.getStoreName();
        }
        throw new BizException("商家入驻信息缺失店铺名称");
    }

    private String createTenantAddress(TenantApply tenantApply) {
        StringBuffer sb = new StringBuffer();

        if (StringUtils.isNotBlank(tenantApply.getStoreAddressProvince())) {
            sb.append(tenantApply.getStoreAddressProvince());
        }

        if (StringUtils.isNotBlank(tenantApply.getStoreAddressCity())) {
            sb.append(tenantApply.getStoreAddressProvince());
        }

        if (StringUtils.isNotBlank(tenantApply.getStoreAddressDetail())) {
            sb.append(tenantApply.getStoreAddressDetail());
        }

        return sb.toString();

    }

    @Override
    public R<TenantApplyAuditDTO> checkTenantApplyResult(TenantApplyCheckDTO tenantApplyCheckDTO) {
        //验证码
        if (!this.checkVerification(tenantApplyCheckDTO.getMobile(), tenantApplyCheckDTO.getType(), tenantApplyCheckDTO.getCode())) {
            throw new BizException("验证码验证失败");
        }

        TenantApplyAuditDTO tenantApplyAuditDTO = this.tenantApplyMapper.getTenantApplyByHeadMobile(tenantApplyCheckDTO.getMobile());

        if (!Objects.isNull(tenantApplyAuditDTO)) {
            return R.success(tenantApplyAuditDTO);
        }

        return R.success(null);
    }

    @Override
    public TenantApplyAuditDTO getTenantApplyByMobile(String headMobile) {
        return this.tenantApplyMapper.getTenantApplyByHeadMobile(headMobile);
    }

    @Override
    public boolean saveTenantApply(TenantApply tenantApply) {
        //个人类型，商家名称为空，默认是店铺名称
        if (StringUtils.isBlank(tenantApply.getMerchantName())
                && tenantApply.getOrganizationType().equals(String.valueOf(OrganizationCodeEnum.PERSONAL.getCode()))) {
            tenantApply.setMerchantName(tenantApply.getStoreName());
        }
        return tenantApplyMapper.saveTenantApply(tenantApply);
    }

    @Override
    public R<Boolean> removeTenantApply(TenantApplyUpdateDTO tenantApplyUpdateDTO) {
        this.removeById(tenantApplyUpdateDTO.getId());
        return R.success(true);

    }

    private boolean checkVerification(String mobile, VerificationCodeType type, String code) {
        String key = CacheKey.buildTenantKey(CacheKey.TENANT_APPLY, type.name(), mobile);
        String cacheCode = cacheRepository.get(key);
        return code.equals(cacheCode);
    }

    private void queryTenantApply(PageParams<TenantApplyPageDTO> params, IPage<TenantApply> page) {
        TenantApplyPageDTO pageDTO = params.getModel();

        Integer total = this.tenantApplyMapper.getTotalOfTenantApplyPage(pageDTO.getMerchantName(),
                pageDTO.getHeadMobile(), pageDTO.getOrganizationType(), pageDTO.getApplyTimeStart(), pageDTO.getApplyTimeEnd(), pageDTO.getAuditState());

        if (total > 0) {
            List<TenantApply> tenantApplies = this.tenantApplyMapper.findTenantApplyPage(pageDTO.getMerchantName(),
                    pageDTO.getHeadMobile(), pageDTO.getOrganizationType(), pageDTO.getApplyTimeStart(), pageDTO.getApplyTimeEnd(),pageDTO.getAuditState(), (page.getCurrent() - 1), page.getSize());

            page.setRecords(tenantApplies);
            page.setTotal(total);
        }
    }
}
